package com.hourse.platform.controller;

import com.alibaba.fastjson.JSON;
import com.hourse.platform.entity.*;
import com.hourse.platform.service.FlowService;
import com.hourse.platform.service.RoleService;
import com.hourse.platform.utils.AppTools;
import com.hourse.platform.utils.StringTools;
import com.hourse.platform.vo.*;
import io.swagger.annotations.Api;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Api(tags = "系统-流程节点管理")
@RestController
@RequestMapping("platform/flow")
@Slf4j
public class FlowController {

    @Autowired
    private FlowService flowService;

    @Autowired
    RoleService roleService;

    @Autowired
    private RedisTemplate redisTemplate;

    @SneakyThrows
    @PostMapping(value = "saveFlow")
    public PageData saveFlow(@RequestBody FlowVO flowVO) {

        FlowEntity flowEntity = (FlowEntity) flowVO.bindEnity(FlowEntity.class);
        flowEntity.setCreateTime(new Date());
        flowService.saveOrUpdate(flowEntity);

        return flowVO.SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "flowList")
    public ResultMsg<List<FlowVO>> flowList() {

        return new ResultMsg(flowService.flowList());
    }

    @SneakyThrows
    @GetMapping(value = "nodeList/{flowId}")
    public ResultMsg<List<FlowNodeVO>> nodeList(@PathVariable String flowId) {

        return new ResultMsg(flowService.nodeList(flowId));
    }

    @SneakyThrows
    @PostMapping(value = "saveFlowNode")
    public PageData saveFlowNode(@RequestBody FlowNodeVO flowNodeVO) {

        FlowNodeEntity flowNodeEntity = (FlowNodeEntity) flowNodeVO.bindEnity(FlowNodeEntity.class);
        flowNodeEntity.setCreateTime(new Date());
        flowService.saveOrUpdate(flowNodeEntity);

        return flowNodeVO.SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "bindInfoList/{flowId}")
    public ResultMsg<List<FlowBindInfoVO>> bindInfoList(@PathVariable String flowId) {

        return new ResultMsg(flowService.bindInfoList(flowId));
    }


    @SneakyThrows
    @PostMapping(value = "saveFlowBindInfo")
    public PageData saveFlowBindInfo(@RequestBody FlowBindInfoVO flowBindInfoVO) {

        FlowBindInfoEntity flowBindInfoEntity =
                (FlowBindInfoEntity) flowBindInfoVO.bindEnity(FlowBindInfoEntity.class);

        flowBindInfoEntity.setCreateTime(new Date());
        flowService.saveOrUpdate(flowBindInfoEntity);

        return flowBindInfoVO.SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "deleteFlowBindInfo/{id}")
    public PageData deleteFlowBindInfo(@PathVariable String id) {

        flowService.delete(id, FlowBindInfoEntity.class);

        return PageData.New().SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "flowInstanceInfo")
    public PageData flowInstanceInfo(@RequestParam(name = "menuId") String menuId,
                                     @RequestParam(name = "instanceId", required = false) String instanceId) {

        FlowInfoVO flowInfoVO = new FlowInfoVO();

        Map<String, String> roleMap = roleService.getRoleMap();

        FlowInstanceEntity flowInstance = null;
        FlowNodeEntity currentNode = null;

        if (StringTools.isNotNull(instanceId)) {
            flowInstance = (FlowInstanceEntity) flowService.getObjectById(instanceId, FlowInstanceEntity.class);
        }

        List<FlowBindInfoVO> allBindList = flowService.bindInfoListByMenuId(menuId);
        List<FlowBindInfoVO> newBindList = new ArrayList<FlowBindInfoVO>();
        // 流程实例存在
        if (flowInstance != null) {
            FlowPath flowPath = (FlowPath) flowService.getObjectById(flowInstance.getId(), FlowPath.class);

            FlowEntity flow = (FlowEntity) flowService.getObjectById(flowPath.getCurrentFlowId(), FlowEntity.class);
            List<FlowBindInfoVO> resultList = new ArrayList<>();
            FlowBindInfoVO flowBindInfoVO = new FlowBindInfoVO();
            flowBindInfoVO.setFlowId(flowPath.getCurrentFlowId());
            flowBindInfoVO.setFlowName(flow.getName());

            resultList.add(flowBindInfoVO);
            flowInfoVO.setFlowList(resultList);
            currentNode = (FlowNodeEntity) flowService.getObjectById(flowInstance.getNextNodeNodeId(), FlowNodeEntity.class);
            setCurrenNodeOpreateInfo(currentNode, flowInfoVO);

        } else {
            // 流程实例不存在 将所有绑定流程返回
            flowInfoVO.setFlowList(allBindList);

            if (allBindList.size() > 1) {
                for (int i = 0; i < allBindList.size(); i++) {
                    String flowId = flowInfoVO.getFlowList().get(i).getFlowId();
                    currentNode = (FlowNodeEntity) flowService.getObjectById(flowService.getFlowFirstNodeId(flowId), FlowNodeEntity.class);

                    String willNodeCode = null;

                    if (currentNode.getRoleCode().equals(roleMap.get(AppTools.getCurrentRoleGroupId()))) {
                        if (redisTemplate.hasKey(instanceId)) {
                            willNodeCode = (String) redisTemplate.opsForValue().get(instanceId);
                        }
                        if (willNodeCode != null) {
                            List<FlowNodeVO> flowNodeVOS = flowService.nodeList(flowId);
                            String flowNextCode = flowNodeVOS.get(1).getRoleCode();
                            if (flowNextCode.equals(willNodeCode)) {
                                setCurrenNodeOpreateInfo(currentNode, flowInfoVO);
                                newBindList.add(flowInfoVO.getFlowList().get(i));
                            }
                        } else {
                            setCurrenNodeOpreateInfo(currentNode, flowInfoVO);
                            newBindList.add(flowInfoVO.getFlowList().get(i));
                        }
                    }
                }
                flowInfoVO.setFlowList(newBindList);
            } else {
                String flowId = flowInfoVO.getFlowList().get(0).getFlowId();
                currentNode = (FlowNodeEntity) flowService.getObjectById(flowService.getFlowFirstNodeId(flowId), FlowNodeEntity.class);
                setCurrenNodeOpreateInfo(currentNode, flowInfoVO);
            }
        }

        return flowInfoVO.SUCCESS();
    }

    /**
     * @功能描述: 【设置节点操作权限信息】
     * @作 者 : Rain
     * @创建时间 : 2020/12/23 14:56
     */
    void setCurrenNodeOpreateInfo(FlowNodeEntity currentNode, FlowInfoVO flowInfoVO) {

        flowInfoVO.setFlowStatus(currentNode.getType());
        flowInfoVO.setCurrentNodeId(currentNode.getId());

        Boolean isCantainsRole = false;
        for (String role : currentNode.getRoleCode().split(",")) {
            isCantainsRole = AppTools.isRole(role);
            if (isCantainsRole) break;
        }

        if ("END".equals(currentNode.getType())) {
            flowInfoVO.setOtherCode(JSON.toJSONString(flowService.getNodeParams(currentNode.getId())));
            //flowInfoVO.setRoleCode(currentNode.getRoleCode());
            flowInfoVO.setRoleCode((String) AppTools.getCurrentRoleGroupId());
            flowInfoVO.setOpreateStatus("N");
        } else if (isCantainsRole || AppTools.isAdmin()) {
            flowInfoVO.setOtherCode(JSON.toJSONString(flowService.getNodeParams(currentNode.getId())));
            //flowInfoVO.setRoleCode(currentNode.getRoleCode());
            flowInfoVO.setRoleCode((String) AppTools.getCurrentRoleGroupId());
            flowInfoVO.setOpreateStatus("Y");
        } else {
            flowInfoVO.setOpreateStatus("N");
        }
    }

    @SneakyThrows
    @GetMapping(value = "flowInstanceNextNode")
    public PageData flowInstanceNextNode(@RequestParam(name = "flowId") String flowId,
                                         @RequestParam(name = "instanceId", required = false) String instanceId) {

        List data = flowService.getInstanceNextNode(flowId, instanceId);

        return PageData.New().SUCCESS(data);
    }

    @SneakyThrows
    @PostMapping(value = "sendFlow")
    public PageData sendFlow(@RequestBody FlowProcessVO flowProcessVO) {

        flowService.sendFlow(flowProcessVO);


        return PageData.New().SUCCESS();
    }


    @SneakyThrows
    @GetMapping(value = "flowOprateList/{instanceId}")
    public PageData flowOprateList(@PathVariable String instanceId) {


        return new ResultMsg(flowService.flowOprateList(instanceId));
    }

    @GetMapping(value = "flowStep/{flowId}/{instanceId}")
    public PageData flowStep(@PathVariable String flowId, @PathVariable String instanceId) {

        return new ResultMsg(flowService.nodeList(flowId, instanceId));
    }

    @SneakyThrows
    @PostMapping(value = "saveFlowParams")
    public PageData saveFlowParams(@RequestBody FlowParamsVO flowParamsVO) {

        FlowParamsEntity FlowParams = (FlowParamsEntity) flowParamsVO.bindEnity(FlowParamsEntity.class);
        flowService.saveOrUpdate(FlowParams);
        return flowParamsVO.SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "deleteFlowParams/{id}")
    public PageData deleteFlowParams(@PathVariable String id) {

        flowService.deleteFlowParams(id);

        return PageData.New().SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "flowParamsList/{flowId}")
    public PageData flowParamsList(@PathVariable String flowId) {

        return new ResultMsg(flowService.flowParamsList(flowId));
    }


    @SneakyThrows
    @PostMapping(value = "saveFlowNodeParams")
    public PageData saveFlowNodeParams(@RequestBody FlowNodeParamsVO flowNodeParamsVO) {

        FlowNodeParamsEntity FlowNodeParams =
                (FlowNodeParamsEntity) flowNodeParamsVO.bindEnity(FlowNodeParamsEntity.class);
        flowService.saveOrUpdate(FlowNodeParams);
        return flowNodeParamsVO.SUCCESS();
    }

    @SneakyThrows
    @GetMapping(value = "flowNodeParamsList/{flowId}/{nodeId}")
    public PageData flowNodeParamsList(@PathVariable String flowId, @PathVariable String nodeId) {


        return new ResultMsg(flowService.flowNodeParamsList(flowId, nodeId));
    }

    /**
     * @功能描述: 【删除节点参数】
     * @作 者 : Rain
     * @创建时间 : 2021/1/27 13:30
     */
    @SneakyThrows
    @GetMapping(value = "deleteFlowNodeParams/{nodeId}/{paramsId}")
    public PageData deleteFlowNodeParams(@PathVariable String nodeId, @PathVariable String paramsId) {

        flowService.deleteFlowNodeParams(nodeId, paramsId);

        return PageData.New().SUCCESS();
    }

    /**
     * @功能描述: 【删除节点】
     * @作 者 : Rain
     * @创建时间 : 2021/1/27 13:30
     */
    @SneakyThrows
    @GetMapping(value = "deleteFlowNode/{nodeId}")
    public PageData deleteFlowNode(@PathVariable String nodeId) {

        flowService.deleteFlowNode(nodeId);

        return PageData.New().SUCCESS();
    }

    /**
     * @功能描述: 【绑定子流程】
     * @作 者 : Rain
     * @创建时间 : 2021/1/26 22:07
     */
    @SneakyThrows
    @PostMapping(value = "addBindFlow")
    public PageData addBindFlow(@RequestBody FlowChildrenBindVO flowChildrenBindVO) {
        FlowChildrenBindEntity flowChildrenBind =
                (FlowChildrenBindEntity) flowChildrenBindVO.bindEnity(FlowChildrenBindEntity.class);
        flowService.saveOrUpdate(flowChildrenBind);
        return flowChildrenBindVO.SUCCESS();
    }

    /**
     * @功能描述: 【子流程列表】
     * @作 者 : Rain
     * @创建时间 : 2021/1/26 22:28
     */
    @SneakyThrows
    @GetMapping(value = "getBindFlowList/{flowId}/{nodeId}")
    public PageData getBindFlowList(@PathVariable String flowId, @PathVariable String nodeId) {

        return new ResultMsg(flowService.getBindFlowList(flowId, nodeId));
    }

}
